package cn.wolfcode.shiro;

import cn.wolfcode.domain.Employee;
import cn.wolfcode.mapper.EmployeeMapper;
import cn.wolfcode.mapper.PermissionMapper;
import cn.wolfcode.mapper.RoleMapper;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * 自定义数据源:提供数据给shiro使用
 *
 */
@Component
public class CustomRealm extends AuthorizingRealm{

    @Autowired
    private EmployeeMapper employeeMapper;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private PermissionMapper permissionMapper;

    @Autowired//注入spring容器中的凭证匹配器
    public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher){
        super.setCredentialsMatcher(credentialsMatcher);
    }

    /**
     *提供认证信息
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //通过token令牌获取到数据名
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
        String username = usernamePasswordToken.getUsername();
        //查询数据库中是否存在该用户名
        Employee employee = employeeMapper.selectByName(username);
        //如果存在 就封装到info 返回给shiro使用
        if (employee!=null){
            //如果存在,就把用户的用户名,密码封装到 AuthenticationInfo 中,
            // 最后返回给 shiro 使用
            //第一个参数:用户对象 第二个: 用户的真正密码
            // 第三个:加密的盐;第四个:当前数据源的名字(对于现在的我们没用)
            return new SimpleAuthenticationInfo(employee,employee.getPassword(),
                    ByteSource.Util.bytes(employee.getName()),this.getName());
        }
        //用户名不存在的话,返回null
        return null;
    }

    /**
     *  提供授权信息 (提供当前用户拥有的数据)
     *  每一次shiro需要进行权限判断的时候(编程式,注解式,标签式)
     *  都会调用该方法获取员工的数据来做判断
     * @param principal
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
        System.out.println("=================");
        //获取当前登陆用户的对象
        //获取主体对象
        //Subject subject = SecurityUtils.getSubject();
        //如果框架没有提供 PrincipalCollection principalCollection 可以用工具类获取
        //Employee employee = (Employee)subject.getPrincipal();
        //如果框架有提供 PrincipalCollection principalCollection 可以直接获取(需要强转)
        Employee employee = (Employee)principal.getPrimaryPrincipal();
        //获取info  它里边的数据就是登录用户里边的权限和角色的信息(正确数据)
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //判断是否为超级管理员
        if (!employee.isAdmin()){
            //根据员工 id 查询员工的角色编码集合
            List<String> roles = roleMapper.selectSnByEmpId(employee.getId());
            info.addRoles(roles);
            //根据员工id查询员工的权限表达式集合
            List<String> expressions = permissionMapper.selectExpressionByEmpId(employee.getId());
            info.addStringPermissions(expressions);
        }else {
            //通配符
            info.addStringPermission("*:*");
            info.addRole("ADMIN");
        }
        return info;
    }
}
